// 这里面装的是MySQL的一些接口函数，用于程序对用户在数据库中的数据进行增删查改
#pragma once

#include "util.hpp"
#include <mutex>

class Mysql_api
{
public:
    Mysql_api(const char *user, const char *passwd, const char *host, const char *db, unsigned int port, const char *unix_socket = NULL, unsigned long clientflag = 0, const char *chara = "utf8")
    {
        _mysql = mysql_util::Mysql_create(user, passwd, host, db, port, unix_socket, clientflag, chara);
    }
    ~Mysql_api()
    {
        mysql_util::Mysql_close(_mysql);
    }

    // 更换使用数据库
    bool Mysql_Changsdb(const string &db)
    {
        mysql_util::Changs_db(_mysql, db.c_str());
    }

    // 注册用户接口 user为已经反序列化之后的结果
    bool Insert(Json::Value user)
    {
        // 使用MD5对密码进行加密
#define INSERT_USER "insert into user values (NULL, '%s', MD5('%s'), 1000, 0, 0);"
        string query_str;
        query_str.resize(100);
        sprintf(&query_str[0], INSERT_USER, user["username"].asCString(), user["password"].asCString());
        // 需要查看当前待注册用户名是否已经被注册了。
        {
            // 防止多线程情况下句柄被污染导致结果与预期不一致所以上锁。
            unique_lock<mutex> lock(_mutex);
            Json::Value temp;
            if (Select_user(user["username"].asCString(), temp))
            {
                DLOG("该用户 %s 已被注册", user["username"].asCString());
                return false;
            }
            return mysql_util::Query(_mysql, query_str.c_str());
        }
    }

    // 通过查询用户名返回用户信息
    bool Select_user(const char *username, Json::Value &info)
    {
#define SELECT_USER "select * from user where username = '%s';"
        string query_str;
        query_str.resize(100);
        sprintf(&query_str[0], SELECT_USER, username);
        mysql_util::Query(_mysql, query_str.c_str());
        MYSQL_RES *result = mysql_store_result(_mysql);
        // 正常情况下只返回0行或者一行数据。
        int ret = mysql_num_rows(result);
        if (!ret)
        {
            DLOG("%s 用户不存在!", username);
            return false;
        }
        MYSQL_ROW row = mysql_fetch_row(result);

        info["id"] = (Json::UInt64)stol(row[0]); // 将字符串row[0]强转成数字再转换成Json形式的整形。
        info["score"] = (Json::UInt64)stoi(row[3]);
        info["total_count"] = stoi(row[4]);
        info["win_count"] = stoi(row[5]);
        mysql_free_result(result); // 清空结果集
        return true;
    }

    // 通过id查询返回用户信息
    bool Select_id(unsigned int id, Json::Value &info)
    {
#define SELECT_ID "select * from user where id = %d"
        string query_str;
        query_str.resize(100);
        sprintf(&query_str[0], SELECT_ID, id);
        mysql_util::Query(_mysql, query_str.c_str());
        MYSQL_RES *result = mysql_store_result(_mysql);
        // 正常情况下只返回0行或者一行数据。
        int ret = mysql_num_rows(result);
        if (!ret)
        {
            DLOG("%d 号用户不存在!", id);
            return false;
        }
        MYSQL_ROW row = mysql_fetch_row(result);

        info["username"] = row[1]; // 将字符串row[0]强转成数字再转换成Json形式的整形。
        info["score"] = (Json::UInt64)stoi(row[3]);
        info["total_count"] = stoi(row[4]);
        info["win_count"] = stoi(row[5]);
        mysql_free_result(result); // 清空结果集
        return true;
    }

    // 用户登录接口
    bool Login_user(Json::Value user)
    {
#define LOGIN_USER "select * from user where username = '%s' and password = MD5('%s');"
        string query_str;
        query_str.resize(100);
        sprintf(&query_str[0], LOGIN_USER, user["username"].asCString(), user["password"].asCString());
        mysql_util::Query(_mysql, query_str.c_str());
        MYSQL_RES *result = mysql_store_result(_mysql);
        int ret = mysql_num_rows(result);
        if (ret > 0)
        {
            mysql_free_result(result);
            return true;
        }
        return false;
    }

    // 当玩家胜利时，场数+1，胜场+1，分数+25；
    bool User_Win(unsigned int id)
    {
#define UPDATA_USER_WIN "update user set total_count = total_count + 1, win = win + 1, score = score + 25 where id = %d;"
        string query_str;
        query_str.resize(120);
        sprintf(&query_str[0], UPDATA_USER_WIN, id);
        MYSQL_RES *result;
        cout << query_str << endl;
        if (mysql_util::Query(_mysql, query_str.c_str()))
        {
            DLOG(UPDATA_USER_WIN ", 执行成功");
            return true;
        }
        else
        {
            ELOG(UPDATA_USER_WIN ", 执行失败");
            return false;
        }
    }

    // 当玩家失败时，场数+1，分数-25
    bool User_Lose(unsigned int id)
    {
#define UPDATA_USER_LOSE "update user set total_count = total_count + 1, score = score - 25 where id = %d;"
        string query_str;
        query_str.resize(100);
        sprintf(&query_str[0], UPDATA_USER_LOSE, id);
        MYSQL_RES *result;
        if (mysql_util::Query(_mysql, query_str.c_str()))
        {
            DLOG(UPDATA_USER_LOSE ", 执行成功");
            return true;
        }
        else
        {
            ELOG(UPDATA_USER_LOSE ", 执行失败");
            return false;
        }
    }

private:
    MYSQL *_mysql;     // mysql操作句柄
    std::mutex _mutex; // 后面用作保护对数据库操作时保证串行操作使句柄不被污染。
};
